package protocol.iec104;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;


import core.ProcessThread;
import process.IEC104Processor;
import protocol.Command;
import protocol.CommandException;
import protocol.funccode.registers.RegTblParserException;
import util.DataUtil;

public class IEC104Command extends Command {

	private String frameType="";
	private int fcCode;
	private int recvIndex=0;
	private int hostRcvIndex=0;
	private int transReason=0;
	
	
	public int getTransReason() {
		return transReason;
	}

	public void setTransReason(int transReason) {
		this.transReason = transReason;
	}

	public int getHostRcvIndex() {
		return hostRcvIndex;
	}

	public void setHostRcvIndex(int hostRcvIndex) {
		this.hostRcvIndex = hostRcvIndex;
	}

	public int getRecvIndex() {
		return recvIndex;
	}

	public void setRecvIndex(int recvIndex) {
		this.recvIndex = recvIndex;
	}
	
	public String getFrameType() {
		return frameType;
	}

	public void setFrameType(String frameType) {
		this.frameType = frameType;
	}

	public int getFcCode() {
		return fcCode;
	}
	public String getStrFccode(){
		return String.valueOf(this.fcCode);
	}

	public void setFcCode(int fcCode) {
		this.fcCode = fcCode;
	}

	public IEC104Command(String s) throws IEC104Commandexception{
		super();
		// TODO Auto-generated constructor stub
		byte[] data= DataUtil.HexStrToBytes(s);
		int ctrl= data[2]&0xff;
		String sctrl= Integer.toBinaryString(ctrl);
		sctrl= DataUtil.LFillWith(sctrl, "0", 8);
		if (sctrl.charAt(7)=='0'){
			this.frameType="I";
		}else {
			if (sctrl.charAt(6)=='0'){
				this.frameType="S";
			} else{
				this.frameType="U";
			}
		}
		if (this.frameType.equals("I")){
			this.fcCode=data[6]&0xff;
			this.transReason= data[8]&0xff;
		}else{
			this.fcCode=data[2]&0xff;
			if (this.frameType.equals("S")){
				this.hostRcvIndex=((data[4]&0xff)+(data[5]&0xff)*256)/2;
			}
		}
		
	}
	interface IEC104CommandInitializer {
		public void init(IEC104Command cmd);
		public void decode(IEC104Command command, ProcessThread thd) throws Exception;
	}
	private abstract static class cIEC104CommandInitializer implements IEC104CommandInitializer{
		public void init(IEC104Command cmd){
			
		}
	}
	
	private static final Map<String, IEC104CommandInitializer> initializerMap
	= new HashMap<String, IEC104CommandInitializer>();

    static {
    	initializerMap.put("7",new cIEC104CommandInitializer(){
    		public void decode(IEC104Command command, ProcessThread thd) throws Exception{
				byte[] frame= IEC104FrameEncode.genUframe(new byte[]{11});
				thd.sendBytes(frame);
			}
    		
    	}
    	);
    	initializerMap.put("1",new cIEC104CommandInitializer(){
    		public void decode(IEC104Command command, ProcessThread thd) throws Exception{
    			thd.setHostRecvIndex(command.getHostRcvIndex());
    			
			}
    		
    	}
    	);
    	initializerMap.put("100",new cIEC104CommandInitializer(){
    		public void decode(IEC104Command command, ProcessThread thd) throws Exception{
    			IEC104Processor.INSTANCE.processRtData(command, thd);
    			
			}	
    	}
    	
    	);
    	
    	initializerMap.put("67",new cIEC104CommandInitializer(){
    		public void decode(IEC104Command command, ProcessThread thd) throws Exception{
    			byte uFrame [] = IEC104FrameEncode.genUframe(new byte[]{(byte) 131});
    			thd.sendBytes(uFrame);
			}	
    	}
    	
    	);
    	
    }
    private static final Logger logger = Logger.getLogger(IEC104Command.class);
	@Override
	public void decode(ProcessThread thd) throws SQLException {
		// TODO Auto-generated method stub
		String funcCode = this.getStrFccode();
		IEC104CommandInitializer cmdInit = initializerMap.get(funcCode);
    	if (cmdInit == null) {
    		logger.error("unsupported func code:"+(funcCode));
    	} else {
    		try {
				cmdInit.decode(this, thd);
			} catch (RegTblParserException e) {
	    		logger.error("data segment error", e);
	        
	        } catch (CommandException e) {
	            logger.error("ieccommand error", e);
	        } catch(SQLException e) {
	        	throw e;
	        } catch (NullPointerException e){
	        	throw e;
	        }
	        catch (Exception e) {
	        	throw new RuntimeException(e);
	        }
    	}

	}

	

}
